//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Workflow.ComponentModel;
using System.Collections;
using System.Collections.Specialized;
using System.Workflow.ComponentModel.Design;
using System.ComponentModel.Design;
using Microsoft.Research.ScientificWorkflow.NetCDF.CSharpAPI;
using System.Workflow.ComponentModel.Compiler;

using Microsoft.Research.ScientificWorkflow;
using Microsoft.Research.ScientificWorkflow.Helpers;

using System.IO;
using WorkflowData;

namespace Microsoft.Research.ScientificWorkflow.Activities
{
    [Name("Hyper Cube Writer")]
    [Description("Writes the hyper cube to a new nc file")]
    [WorkflowCategory("NetCdf")]
    [Designer(typeof(HyperCubeSchemaGeneratorDesigner), typeof(IDesigner))]
    public class WriteHyperCube : Activity
	{
		private const string HyperCuberPropertyName = "HyperCubeProvider";

        #region Dependency Properties

		public static DependencyProperty FileFolderPathProperty = DependencyProperty.Register("FileFolderPath", 
            typeof(string), typeof(WriteHyperCube));

        [RequiredInputParam]
        [Name("Out File Path", "Path for Nc file")]
        [Description("Path where the nc file would be created.")]
		public string FileFolderPath
		{
			get
			{
				return ((string)(base.GetValue(WriteHyperCube.FileFolderPathProperty)));
			}
			set
			{
				base.SetValue(WriteHyperCube.FileFolderPathProperty, value);
			}
		}


		public static DependencyProperty FileNameProperty = DependencyProperty.Register("FileName", 
            typeof(string), typeof(WriteHyperCube));

        [RequiredInputParam]
        [Name("Out File Name", "Name of the ouput nc file with extn")]
        [Description("Name of the output nc file.")]
		public string FileName
		{
			get
			{
				return ((string)(base.GetValue(WriteHyperCube.FileNameProperty)));
			}
			set
			{
				base.SetValue(WriteHyperCube.FileNameProperty, value);
			}
		}

        public static DependencyProperty InputCubeProperty =
            DependencyProperty.Register("InputCube", typeof(HyperCube), typeof(WriteHyperCube));

        [RequiredInputParam]
        [Name("Input HyperCube")]
        [Description("Hyper Cube with data to be written to the netCDF file.")]
        public HyperCube InputCube
        {
            get
            {
                return ((HyperCube)(base.GetValue(WriteHyperCube.InputCubeProperty)));
            }
            set
            {
                base.SetValue(WriteHyperCube.InputCubeProperty, value);
            }
        }

        #endregion

		protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
		{
			NetCDFWriterEx.CreateFile(System.IO.Path.Combine(this.FileFolderPath, this.FileName)
                                    , this.InputCube);

			//Following is to simply writing to a txt file
			//this.DummyWritter(netCDFFile);

            return ActivityExecutionStatus.Closed;
		}

		private void DummyWritter(NetCDFFile netCDFFile)
		{
			using (StreamWriter sw = new StreamWriter(System.IO.Path.Combine(this.FileFolderPath, this.FileName + ".Dummy.txt")))
			{
				HyperCube cube = netCDFFile.HyperCube;

				sw.WriteLine("X Axis:" + netCDFFile.HyperCube.GetAxisLength(HyperCube.Axis.X).ToString() +
							", Y Axis:" + netCDFFile.HyperCube.GetAxisLength(HyperCube.Axis.Y).ToString() +
							", Z Axis:" + netCDFFile.HyperCube.GetAxisLength(HyperCube.Axis.Z).ToString() +
							", T Axis:" + netCDFFile.HyperCube.GetAxisLength(HyperCube.Axis.T).ToString());

				int colCount = cube.Schema.ColumnCount;
				sw.Write("Total Number of Variables in Cube:" + colCount.ToString());
				sw.Write(" Data[X, Y, Z, T] <");
				for (int i = 0; i < cube.Schema.ColumnCount; i++)
				{
					if (i == cube.Schema.ColumnCount - 1 )
						sw.Write(cube.Schema.GetColumnName(i));
					else
						sw.Write(cube.Schema.GetColumnName(i) + " , ");
				}
				sw.WriteLine(">");
				sw.WriteLine();

				HyperCubeDataPoint datapoint;
				for (int m = 0; m < cube.GetAxisLength(HyperCube.Axis.T); m++)
				{
					for (int i = 0; i < cube.GetAxisLength(HyperCube.Axis.X); i++)
					{
						for (int j = 0; j < cube.GetAxisLength(HyperCube.Axis.Y); j++)
						{
							for (int k = 0; k < cube.GetAxisLength(HyperCube.Axis.Z); k++)
							{
								sw.Write("[{0},{1},{2},{3}]<", i, j, k, m);
								for (int kk = 0; kk < cube.Schema.ColumnCount; kk++)
								{
									datapoint = cube[i, j, k, m];
									if (datapoint != null && datapoint[kk] != null)
									{
										if( kk != (cube.Schema.ColumnCount-1) )
											sw.Write("{0},", datapoint[kk].ToString());
										else
											sw.Write("{0}", datapoint[kk].ToString());
									}
									else
									{
										if (kk != (cube.Schema.ColumnCount - 1))
											sw.Write("-,");
										else
											sw.Write("-");
									}
								}
								sw.Write(">  ");
							}
						}
						sw.WriteLine();
					}
				}
				sw.WriteLine();
			}

		}

		#region IPropertyValueProvider Members

        //public ICollection GetPropertyValues(ITypeDescriptorContext typeDescriptorContext)
        //{
        //    StringCollection propertyCollection = new StringCollection();
        //    CompositeActivity root = ActivityHelper.GetRootActivity(this) as CompositeActivity;
        //    foreach (Activity avt in root.Activities)
        //    {
        //        if (avt.GetType().GetInterface("IHyperCubeProvider") != null)
        //        {
        //            propertyCollection.Add(avt.Name);
        //        }
        //    }

        //    return propertyCollection;
        //}

		#endregion
	}
}
